package com.szsky.sky.utils;

import cn.hutool.core.codec.Base64;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;

/**
 * @description: 对原始数据进行AES加密后，再进行十六进制转化；
 **/
@Slf4j
public class AESUtil {

    /*
     * 此处使用AES-128-CBC加密模式，key需要为16位。
     */
    private static Object lock = new Object();
    // 加密秘钥，需要根据各自的key进行分配，请提交key予接口人申请秘钥。16位
    public static String globalKey = "1qaz@WSX)OKM9ijn";
    //偏移向量，无需修改 16位
//    private static String ivParameter = "0000000000000000";
    private static String ivParameter = "zxcv/.,m^TFC7ygv";
    private static final String GAODE_PKCS5 = "AES/CBC/PKCS5Padding";
    private static final String AES = "AES";
    private static Cipher encipher = null;
    private static Cipher decipher = null;

    public AESUtil() {
        try {
            byte[] raw = globalKey.getBytes(StandardCharsets.UTF_8);
            SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
            IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(StandardCharsets.UTF_8));

            encipher = Cipher.getInstance(GAODE_PKCS5);
            encipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

            decipher = Cipher.getInstance(GAODE_PKCS5);
            decipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        } catch (Exception e) {
            log.error("GaoDeAESUtil,Exception:{}", e);
        }
    }

    public AESUtil(String key, String ivParameter) {
        try {
            byte[] raw = key.getBytes(StandardCharsets.UTF_8);
            SecretKeySpec skeySpec = new SecretKeySpec(raw, AES);
            IvParameterSpec iv = new IvParameterSpec(ivParameter.getBytes(StandardCharsets.UTF_8));

            encipher = Cipher.getInstance(GAODE_PKCS5);
            encipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);

            decipher = Cipher.getInstance(GAODE_PKCS5);
            decipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
        } catch (Exception e) {
            log.error("GaoDeAESUtil,Exception:{}", e);
        }
    }

    /**
     * 加密
     *
     * @param sSrc 需要加密的字符串
     * @return 加密后的数据
     * @throws Exception
     */
    public static String encrypt(String sSrc) throws Exception {
        AESUtil aes = new AESUtil();
        byte[] encrypted = null;
        synchronized (lock) {
            encrypted = encipher.doFinal(sSrc.getBytes(StandardCharsets.UTF_8));
        }
        return bytesToHexString(encrypted);
    }

    /**
     * 加密
     *
     * @param sSrc 需要加密的字符串
     * @param key  密钥
     * @return 加密后的数据
     * @throws Exception
     */
    public static String encrypt(String sSrc, String key, String ivParameter) throws Exception {
        AESUtil aes = new AESUtil(key, ivParameter);
        byte[] encrypted = null;
        synchronized (lock) {
            encrypted = encipher.doFinal(sSrc.getBytes(StandardCharsets.UTF_8));
        }
        return bytesToHexString(encrypted);
    }


    /**
     * 解密
     *
     * @param sSrc 需要解密的字符串
     * @return 解密后的数据
     * @throws Exception
     */
    public static String decrypt(String sSrc) throws Exception {
        AESUtil aes = new AESUtil();
        byte[] encrypted1 = hexStringToBytes(sSrc);
        byte[] original = null;
        synchronized (lock) {
            original = decipher.doFinal(encrypted1);
        }
        String originalString = new String(original, StandardCharsets.UTF_8);
        return originalString;
    }

    /**
     * 解密
     *
     * @param sSrc 需要解密的字符串
     * @param key  密钥
     * @return 解密后的数据
     * @throws Exception
     */
    public static String decrypt(String sSrc, String key, String ivParameter) throws Exception {
        AESUtil aes = new AESUtil(key, ivParameter);
        byte[] encrypted1 = hexStringToBytes(sSrc);
        byte[] original = null;
        synchronized (lock) {
            original = decipher.doFinal(encrypted1);
        }
        String originalString = new String(original, StandardCharsets.UTF_8);
        return originalString;
    }

    // byte [] to hex string
    public static String bytesToHexString(byte[] src) {
        StringBuilder stringBuilder = new StringBuilder();
        if (src == null || src.length <= 0) {
            return null;
        }
        for (int i = 0; i < src.length; i++) {
            int v = src[i] & 0xFF;
            String hv = Integer.toHexString(v);
            if (hv.length() < 2) {
                stringBuilder.append(0);
            }
            stringBuilder.append(hv);
        }
        return stringBuilder.toString();
    }

    // hex String to byte []
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    public static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    public static void main(String[] args) throws Exception {

        Long l = System.currentTimeMillis();
        System.out.println("时间戳：" + l);
        // 需要加密的字串
//        String cSrc = "appKey=a3ab6adb84e14dc7aee4fc046367206e&timestamp="+(l + (6*60*1000))+"";//
        String cSrc = "appKey=a3ab6adb84e14dc7aee4fc046367206e&timestamp="+(l )+"";//
        cSrc = "currentVersion=1.0.0.0&appType=iOS&timestamp="+(l + (6*60*1000))+"";
        cSrc = "currentVersion=1.0.0.0&timestamp="+(l + (6*60*1000))+"";
        cSrc = "currentVersion=0.0.0.1&appType=iOS&timestamp="+(l + (6*60*1000))+"";
//        cSrc = "IDRBZ-IAJEU-VX4VC-BFFNB-VSVTV-NGB25";//
        cSrc = "F36U2J9D9T";//
        System.out.println(cSrc);

        AESUtil aesUtil = new AESUtil();
        String enString2 = aesUtil.encrypt(Base64.encode(cSrc.getBytes()));
        System.out.println("加密：" + enString2);
        String deString2 = aesUtil.decrypt(enString2);
        System.out.println("解密：" + Base64.decodeStr(deString2));
    }
}